package com.cml.getway.core.netty;

import com.cml.getway.core.GetwayConfig;
import com.cml.getway.core.LifeCycle;
import com.cml.getway.core.netty.processor.NettyProcessor;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.HttpServerExpectContinueHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * 姓名：陈茂林
 * 时间：2023/12/20
 * 描述：
 */
@Slf4j
public class NettyHttpServer implements LifeCycle {
    private GetwayConfig getwayConfig;

    private int port = 8888;

    private ServerBootstrap serverBootstrap;

    private EventLoopGroup eventLoopGroupBoss;

    private EventLoopGroup eventLoopGroupWork;

    private NettyProcessor nettyProcessor;

    public  NettyHttpServer(GetwayConfig getwayConfig,NettyProcessor nettyProcessor){
        this.getwayConfig=getwayConfig;
        this.nettyProcessor=nettyProcessor;
        if(getwayConfig.getPort() > 0 && getwayConfig.getPort() < 65535) {
            this.port = getwayConfig.getPort();
        }
        //	初始化NettyHttpServer
        init();
    }
    @Override
    public void init() {
        this.serverBootstrap = new ServerBootstrap();
        if(Epoll.isAvailable()){
            this.eventLoopGroupBoss = new EpollEventLoopGroup(getwayConfig.getEventLoopGroupBossNum(),
                    new DefaultThreadFactory("NettyBossEPoll"));
            this.eventLoopGroupWork = new EpollEventLoopGroup(getwayConfig.getEventLoopGroupWorkNum(),
                    new DefaultThreadFactory("NettyWorkEPoll"));
        }else {
            this.eventLoopGroupBoss = new NioEventLoopGroup(getwayConfig.getEventLoopGroupBossNum(),
                    new DefaultThreadFactory("NettyBossNio"));
            this.eventLoopGroupWork = new NioEventLoopGroup(getwayConfig.getEventLoopGroupWorkNum(),
                    new DefaultThreadFactory("NettyWorkNio"));
        }
    }

    @Override
    public void start() {
        ServerBootstrap handler = this.serverBootstrap
                .group(eventLoopGroupBoss, eventLoopGroupWork)
                .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)			//	sync + accept = backlog
                .option(ChannelOption.SO_REUSEADDR, true)   	//	tcp端口重绑定
                .option(ChannelOption.SO_KEEPALIVE, false)  	//  如果在两小时内没有数据通信的时候，TCP会自动发送一个活动探测数据报文
                .childOption(ChannelOption.TCP_NODELAY, true)   //	该参数的左右就是禁用Nagle算法，使用小数据传输时合并
                .childOption(ChannelOption.SO_SNDBUF, 65535)	//	设置发送数据缓冲区大小
                .childOption(ChannelOption.SO_RCVBUF, 65535)	//	设置接收数据缓冲区大小
                .localAddress(new InetSocketAddress(this.port))
                .childHandler(new ChannelInitializer<Channel>() {

                    @Override
                    protected void initChannel(Channel ch) throws Exception {
                        ch.pipeline().addLast(
                                new HttpServerCodec(),
                                new HttpObjectAggregator(getwayConfig.getMaxContentLength()),
//                                new HttpServerExpectContinueHandler(),
                                //new NettyServerConnectManagerHandler(),
                                new NettyHttpServerHandler(nettyProcessor)
                        );
                    }
                });

        if(getwayConfig.isNettyAllocator()) {
            handler.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
        }

        try {
            this.serverBootstrap.bind().sync();
            log.info("< ============= getwayConfig Server StartUp On Port: " + this.port + "================ >");
        } catch (Exception e) {
            throw new RuntimeException("this.serverBootstrap.bind().sync() fail!", e);
        }
    }

    @Override
    public void shutdown() {

    }

    public EventLoopGroup getEventLoopGroupWork() {
        return this.eventLoopGroupWork;
    }
}
